#ifndef __SHM_HPP__
#define __SHM_HPP__

#include <iostream>
#include<cstdio>
#include<string>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<sys/types.h>
#include<unistd.h>

std::string gpathname=".";
int gproj_id=0x66;
int gdefaultsize=4096;//共享内存大小


class SharedMemory
{
private:
    bool CreateHelper(int flags)
    {
        //创建建值
        _key=ftok(gpathname.c_str(),gproj_id);
        if(_key<0)
        {
            perror("ftok");
            return false;
        }
        printf("形成键值成功:0x%x\n",_key);

        _shmid=shmget(_key,_size,flags);//创建全新的shm
        if(_shmid<0)
        {
            perror("shmget");
            return false;
        }
        printf("shmid:%d\n",_shmid);
        return true;

    }
public:
    SharedMemory(int size=gdefaultsize)
        :_size(size)
        ,_key(0)
        ,_shmid(-1)
        ,_start_addr(nullptr)
        ,_windex(0)
        ,_rindex(0)
        ,_datastart(nullptr)
        ,_num(nullptr)
    {
    }
    bool Create()
    {
        return CreateHelper(IPC_CREAT|IPC_EXCL|0666);
    }
    bool Get()
    {
        return CreateHelper(IPC_CREAT);
    }

    bool Attach()
    {
        _start_addr=shmat(_shmid,nullptr,0);//返回值void* 为通用指针
        //shmat成功返回共享内存段连接到进程地址空间的起始地址，失败返回(void*)-1
        if((long long)_start_addr==-1)
        {
            perror("shmat");
            return false;
        }
        std::cout<<"挂接共享内存"<<std::endl;

        printf("_start_addr:%p\n",_start_addr);
        _num=(int*)_start_addr;
        _datastart=(char*)_start_addr+sizeof(int);
        return true;
    }
    
    void SetZero()
    {
        *_num=0;
    }
    bool Detach()
    {
        int n=shmdt(_start_addr);
        if(n<0)
        {
            perror("shmdt");
            return false;
        }
        std::cout<<"移除共享内存"<<std::endl;
        return true;
    }
    void AddChar(char ch)
    {
        if(*_num==_size) return;
        //直接写，一个字节一个字符，不能超过4096
        ((char*)_datastart)[_windex++]=ch;
        ((char*)_datastart)[_windex]='\0';
        std::cout<<"debug:"<<_windex<<","<<ch<<std::endl;
        _windex%=_size;
        (*_num)++;
    }
    void PopChar(char* ch)
    {
        if(*_num==0) return;
        *ch=((char*)_datastart)[_rindex++];
        _rindex%=_size;
        (*_num)--;
        printf("%d\n",*_num);
        printf("%s\n",_datastart);
    }

    bool RemoveShm()
    {
        int n=shmctl(_shmid,IPC_RMID,nullptr);
        if(n<0)
        {
            perror("shmctl");
            return false;
        }
        std::cout<<"删除shm成功"<<std::endl;
        return true;
    }
    void PrintAttr()
    {
        struct shmid_ds ds;
        int n=shmctl(_shmid,IPC_STAT,&ds);
        if(n<0)
        {
            perror("shmctl");
            return;
        }

        printf("key:0x%x\n",ds.shm_perm.__key);
        printf("size:%ld\n",ds.shm_segsz);
        printf("atime:%lu\n",ds.shm_atime);
        printf("nattach:%ld\n",ds.shm_nattch);

    }
    ~SharedMemory()
    {
    }

private:
    key_t _key;//int
    int _size;
    int _shmid;
    void* _start_addr;
    int* _num;
    char* _datastart;
    int _windex;
    int _rindex;
};

#endif